package org.example.judge_contest.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import org.example.judge_common.entity.PageResult;
import org.example.judge_common.rank.AllUserRank;
import org.example.judge_common.util.IdWorker;
import org.example.judge_common.util.MyUtils;
import org.example.judge_contest.mapper.ContestRecordMapper;
import org.example.judge_common.rank.RankList;
import org.example.judge_common.rank.RankUser;
import org.example.judge_contest.service.ContestProblemService;
import org.example.judge_contest.service.ContestRecordService;
import org.example.judge_contest.service.ContestRegisterService;
import org.example.judge_contest.service.ContestService;
import org.example.judge_pojo.Contest;
import org.example.judge_pojo.ContestProblem;
import org.example.judge_pojo.ContestRecord;
import org.example.judge_pojo.ContestRegister;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service("ContestRecordServiceImpl")
public class ContestRecordServiceImpl extends ServiceImpl<ContestRecordMapper, ContestRecord> implements ContestRecordService {

    @Autowired
    private  IdWorker idWorker;
    @Qualifier("ContestRegisterServiceImpl")
    @Autowired
    private ContestRegisterService contestRegisterService;

    @Qualifier("ContestProblemServiceImpl")
    @Autowired
    private ContestProblemService contestProblemService;

    @Qualifier("ContestServiceImpl")
    @Autowired
    private ContestService contestService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public boolean save(ContestRecord entity) {
        entity.setId(idWorker.nextId().toString());
        entity.setIsFirst(1);
        entity.setStatus(1); //默认无效
        if(entity.getCreateTime()==null)entity.setCreateTime(new Date(System.currentTimeMillis()));
//        redisTemplate.opsForValue().set(entity.getId(),JSON.toJSONString(entity),2,TimeUnit.MINUTES);
        redisTemplate.opsForValue().set(entity.getSubmitId()+"_redis",JSON.toJSONString(entity),2,TimeUnit.MINUTES);
        return super.save(entity);
    }

    @Override
    public boolean updateById(ContestRecord entity) {
        redisTemplate.opsForValue().set(entity.getId(),null,2,TimeUnit.MINUTES);
        return super.updateById(entity);
    }

    @Override
    public List<ContestRecord> list(String userId, String contestId, String problemId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId).eq("contest_id",contestId).eq("problem_id",problemId);
        wrapper.isNotNull("is_ac").eq("status",0);
        return this.list(wrapper);
    }

    @Override
    public ContestRecord getFirstAc(String userId, String contestId, String problemId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId).eq("contest_id",contestId).eq("problem_id",problemId);
        wrapper.eq("is_ac",0).orderByAsc("create_time");
        wrapper.eq("status",0);
        PageHelper.startPage(1,1,false);
        return super.getOne(wrapper);
    }

    @Override
    public ContestRecord lastSubmit(String userId, String contestId, String problemId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId).eq("contest_id",contestId).eq("problem_id",problemId);
        wrapper.orderByDesc("create_time");
        wrapper.isNotNull("is_ac").eq("status",0);
        PageHelper.startPage(1,1,false);
        return super.getOne(wrapper);
    }

    @Override
    public ContestRecord getBySubmitId(String id) {
        Object o = redisTemplate.opsForValue().get(id + "_redis");
        ContestRecord one = null;

        if(o==null){
            QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
            wrapper.eq("submit_id",id);
//            wrapper.isNotNull("is_ac");
            one = super.getOne(wrapper);
        }else {
            one = JSON.parseObject(((String) o),ContestRecord.class);
        }
        return one;
    }

    @Override
    public int count(String userId, String contestId, String problemId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq(MyUtils.isNotEmpty(userId),"user_id",userId).
                eq(MyUtils.isNotEmpty(contestId),"contest_id",contestId).
                eq(MyUtils.isNotEmpty(problemId),"problem_id",problemId);
        wrapper.isNotNull("is_ac").eq("status",0);
        if(MyUtils.isNotEmpty(problemId))wrapper.select("problem_id");
        else wrapper.select("distinct problem_id");
        return this.count(wrapper);
    }

    @Override
    public ContestRecord getFirstAc(String contestId, String problemId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id",contestId).eq("problem_id",problemId).eq("status",0);
        wrapper.eq("is_ac",0).orderByAsc("create_time");
        PageHelper.startPage(1,1,false);
        return super.getOne(wrapper);
    }

    /**
     * 获取参与竞赛提交的所有用户
     * @param contestId
     * @return
     */
    private List<ContestRecord> listUserByContestId(String contestId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id",contestId).eq("status",0);
        wrapper.select("DISTINCT user_id");
        return this.list(wrapper);
    }

    @Override
    public RankList rank(String contestId,boolean cache) {
//        List<ContestRecord> list = this.listUserByContestId(contestId); //所有的提交记录
        //获取缓存
        RankList res = null;
        Object o1 = null;
        if(cache) o1 = redisTemplate.opsForValue().get(RankList.getRedisKey(contestId));
        if(o1!=null){
            res = JSON.parseObject(((String) o1),RankList.class);
        }

        if(res != null)return res;
        //获取比赛的信息
        Contest contest = contestService.getById(contestId);

        //获取所有的用户
        List<ContestRegister> list = contestRegisterService.list(contestId);
        //获取所有的题目
        List<ContestProblem> contestProblems = contestProblemService.listByContestId(contestId);
        //生成榜单
        res = new RankList();
        res.setContestId(contestId);
        res.setContestName(contest.getTitle());
        res.setAuth(contest.getAuth());
        if(contest.getSealRank()==0)res.setSealRankTime(contest.getSealRankTime());
        res.setUsers(new ArrayList<>(list.size()));
        List<RankUser> users = res.getUsers();
        //提取每个用户
        for (ContestRegister o : list) {  //获取用户
            RankUser rankUser = new RankUser();
            rankUser.setUserId(o.getUserId());
            rankUser.setUsername(o.getUsername());
            rankUser.setSchool(o.getSchoolName());
            rankUser.setRecords(new ArrayList<>());
            List<ContestRecord> records = rankUser.getRecords();  //题目提交情况
            users.add(rankUser);
            //获取每个用户的每一题的提交记录
            for (ContestProblem contestProblem : contestProblems) {
                String problemId = contestProblem.getProblemId();
                // 用户题目第一次AC记录
                ContestRecord firstAc = this.getFirstAc(o.getUserId(), contestId, problemId);

                if(firstAc!=null){//该题目已通过
                    //封榜，消除信息
                    if (contest.getSealRank()==0&&  //是否开启封榜
                            firstAc.getCreateTime().getTime()>=contest.getSealRankTime().getTime()&&//封榜时间已到
                            System.currentTimeMillis()<contest.getEndTime().getTime()) {  //比赛未结束
                        firstAc.setTime(-1);
                        firstAc.setIsAc(-1);
                        firstAc.setIsFirst(-1);
                        firstAc.setSubmitSum(firstAc.getSubmitSum()+1);
                    }else{
                        rankUser.setAc(rankUser.getAc()+1); //通过题目+1
                        rankUser.setTime(rankUser.getTime()+ firstAc.getTime());  //罚时
                    }

                }else{
                    //该用户最后一次提交记录
                    firstAc = this.lastSubmit(o.getUserId(),contestId,problemId);
//                    System.out.println(firstAc);
                    //封榜，消除信息
                    if (firstAc!=null&&contest.getSealRank()==0&&  //开启封榜且非第一次提交
                            firstAc.getCreateTime().getTime()>=contest.getSealRankTime().getTime()&&//封榜时间已到
                            System.currentTimeMillis()<contest.getEndTime().getTime()) {  //比赛未结束
                        firstAc.setTime(-1);
                        firstAc.setIsAc(-1);
                    }else if(firstAc!=null) { //未封榜

                    }else {  //题目未有提交记录
                        firstAc = new ContestRecord();
                        firstAc.setContestId(contestId);
                        firstAc.setUserId(o.getUserId());
                        firstAc.setProblemId(problemId);
                    }
                }

                records.add(firstAc);
            }
        }
        //排序
        res.sort();
        //加入缓存1小时
        redisTemplate.opsForValue().set(RankList.getRedisKey(contestId), JSON.toJSONString(res),1, TimeUnit.HOURS);
        return res;
    }

    @Override
    public int countContestSubmit(String contestId, String problemId, Integer isAc) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id",contestId).eq("problem_id",problemId);
//        wrapper.select("distinct problem_id");
        if(isAc!=null)wrapper.eq("is_ac",isAc);
        return super.count(wrapper);
    }

    @Override
    public boolean isAc(String contestId, String problemId, String userId,Integer isAc) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id",contestId).eq("problem_id",problemId).eq("user_id",userId);
//        wrapper.eq("status",0);
        if(isAc!=null)wrapper.eq("is_ac",isAc);
        return super.count(wrapper)>0;
    }

    @Override
    public PageResult<AllUserRank> getUserRank(Integer page, Integer size,String beginTime) {
        if(page==null||page<1)page = 1;
        if(size==null)size = 10;
        if(MyUtils.isEmpty(beginTime))beginTime = "1970-01-01";
        List<AllUserRank> allRank = super.baseMapper.getAllRank((page - 1) * size, size,beginTime);
        return new PageResult<AllUserRank>(0l,allRank);
    }

    @Override
    public Integer getAcceptProblemRank(String contestId, String problemId) {
        return super.baseMapper.getAcceptProblemRank(contestId,problemId);
    }

    @Override
    public Integer ContestCount(String userId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId).eq("status",0);
        wrapper.select("DISTINCT contest_id");
        return super.count(wrapper);
    }

    @Override
    public Integer acceptProblemCount(String userId, String contestId) {
        QueryWrapper<ContestRecord> wrapper = new QueryWrapper<>();
        wrapper.eq(MyUtils.isNotEmpty(userId),"user_id",userId).
                eq(MyUtils.isNotEmpty(contestId),"contest_id",contestId);
        wrapper.eq("is_ac",0).eq("status",0);
        wrapper.select("distinct problem_id");
        return this.count(wrapper);
    }
}
